﻿/********************************************************************************
** 作者： Mick
** 邮箱： zheng_jinfan@126.com
** 主页： http://www.zhengjinfan.cn
** 创始时间：2016-2-17
** 描述：
**      [辅助类]Excel操作辅助类
*********************************************************************************/

using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Text;
using System.Web;
using BestEasyCMS.Framework.Extension;
using NPOI.HSSF.UserModel;
using NPOI.SS.UserModel;

namespace BestEasyCMS.Framework.Util
{
    /// <summary>
    /// [辅助类]Excel操作辅助类
    /// </summary>
    public class ExcelUtil
    {
        #region 字符串拼接xls文件内容并输出

        /*
        /// <summary>
        /// 根据表格和文件名, 生成Excel文件, 并输出到客户端
        /// </summary>
        /// <param name="ds"></param>
        /// <param name="fileName"></param>
        public static void CreateExcel(DataTable table, string fileName)
        {
            StringBuilder sb = new StringBuilder();

            sb.Append("<table align=\"center\" style='border-collapse:collapse;table-layout:fixed'>");
            if (table.Columns.Count > 0)
            {
                //写标题
                sb.Append("<tr>");
                foreach (DataColumn col in table.Columns)
                {
                    sb.AppendFormat("<td><b>{0}</b></td>", col);
                }
                sb.Append("</tr>");

                //写数据
                foreach (DataRow row in table.Rows)
                {
                    sb.Append("<tr>");
                    foreach (var cell in row.ItemArray)
                    {
                        sb.AppendFormat("<td style= 'vnd.ms-excel.numberformat:@ '>{0}</td>", cell);
                    }
                    sb.Append("</tr>");
                }
            }

            string result = getWrapper().FormatWith(sb.ToStr());

            HttpContext.Current.Response.Clear();
            HttpContext.Current.Response.Buffer = true;
            HttpContext.Current.Response.Charset = "GB2312";
            HttpContext.Current.Response.AppendHeader("Content-Disposition", "attachment;filename=" + fileName);
            HttpContext.Current.Response.ContentEncoding = System.Text.Encoding.GetEncoding("GB2312");  //设置输出流为简体中文
            HttpContext.Current.Response.ContentType = "application/ms-excel";  //设置输出文件类型为excel文件。
            HttpContext.Current.Response.Write(result);
            HttpContext.Current.Response.End();
        }
        */

        #endregion

        /// <summary>   
        /// 用于Web导出   
        /// </summary> 
        /// <param name="dtSource">表头文本 </param>
        /// <param name="strFileName">文件名</param>   
        public static void CreateExcel(DataTable dtSource, string strFileName)
        {
            HttpContext curContext = HttpContext.Current;

            // 设置编码和附件格式   
            curContext.Response.ContentType = "application/vnd.ms-excel";
            curContext.Response.ContentEncoding = Encoding.UTF8;
            curContext.Response.Charset = "";
            curContext.Response.AppendHeader("Content-Disposition",
                                             "attachment;filename=" + HttpUtility.UrlEncode(strFileName, Encoding.UTF8));

            curContext.Response.BinaryWrite(Export(dtSource).GetBuffer());
            curContext.Response.End();
        }

        /// <summary>   
        /// DataTable导出到Excel的MemoryStream内存流
        /// </summary>   
        /// <param name="dtSource">源DataTable</param>    
        /// <returns>内存流</returns>
        public static MemoryStream Export(DataTable dtSource)
        {
            var workbook = new HSSFWorkbook();
            ISheet sheet = workbook.CreateSheet();
            IDataFormat format = workbook.CreateDataFormat();
            ICellStyle dateStyleDateTime = workbook.CreateCellStyle();//时间格式
            dateStyleDateTime.DataFormat = format.GetFormat("yyyy-MM-dd HH:mm");
            ICellStyle dateStyleMoney = workbook.CreateCellStyle();//金钱
            dateStyleMoney.DataFormat = format.GetFormat("#,##0");
            

            //取得列宽   
            var arrColWidth = new int[dtSource.Columns.Count];
            foreach (DataColumn item in dtSource.Columns)
            {
                arrColWidth[item.Ordinal] = Encoding.GetEncoding(936).GetBytes(item.ColumnName).Length;
            }
            for (int i = 0; i < dtSource.Rows.Count; i++)
            {
                for (int j = 0; j < dtSource.Columns.Count; j++)
                {
                    int intTemp = Encoding.GetEncoding(936).GetBytes(dtSource.Rows[i][j].ToString()).Length;
                    if (intTemp > arrColWidth[j])
                    {
                        arrColWidth[j] = intTemp;
                    }
                }
            }


            int rowIndex = 0;
            if (dtSource.Rows.Count == 0)
            {
                #region 列头及样式

                {
                    IRow headerRow = sheet.CreateRow(0);
                    ICellStyle headStyle = workbook.CreateCellStyle();
                    IFont font = workbook.CreateFont();
                    font.FontHeightInPoints = 12;
                    font.Boldweight = 700;
                    headStyle.SetFont(font);

                    foreach (DataColumn column in dtSource.Columns)
                    {
                        headerRow.CreateCell(column.Ordinal).SetCellValue(column.ColumnName);
                        headerRow.GetCell(column.Ordinal).CellStyle = headStyle;

                        //设置列宽   
                        sheet.SetColumnWidth(column.Ordinal, (arrColWidth[column.Ordinal] + 1)*300);
                    }
                }

                #endregion
            }
            foreach (DataRow row in dtSource.Rows)
            {
                #region 新建表，填充表头，填充列头，样式

                if (rowIndex == 65535 || rowIndex == 0)
                {
                    if (rowIndex != 0)
                    {
                        sheet = workbook.CreateSheet();
                    }

                    #region 表头及样式

                    //{
                    //    //HSSFRow headerRow = sheet.CreateRow(0);
                    //    //headerRow.HeightInPoints = 25;
                    //    //headerRow.CreateCell(0).SetCellValue(strHeaderText);

                    //    HSSFCellStyle headStyle = workbook.CreateCellStyle();
                    //    // headStyle.Alignment = CellHorizontalAlignment.CENTER;
                    //    HSSFFont font = workbook.CreateFont();
                    //    font.FontHeightInPoints = 20;
                    //    font.Boldweight = 700;
                    //    headStyle.SetFont(font);

                    //    //headerRow.GetCell(0).CellStyle = headStyle;

                    //    sheet.AddMergedRegion(new Region(0, 0, 0, dtSource.Columns.Count - 1));
                    //    // headerRow.Dispose();
                    //}

                    #endregion

                    #region 列头及样式

                    {
                        IRow headerRow = sheet.CreateRow(0);


                        ICellStyle headStyle = workbook.CreateCellStyle();
                        // headStyle.Alignment = CellHorizontalAlignment.CENTER;
                        IFont font = workbook.CreateFont();
                        font.FontHeightInPoints = 12;
                        font.Boldweight = 700;
                        headStyle.SetFont(font);


                        foreach (DataColumn column in dtSource.Columns)
                        {
                            headerRow.CreateCell(column.Ordinal).SetCellValue(column.ColumnName);
                            headerRow.GetCell(column.Ordinal).CellStyle = headStyle;

                            //设置列宽   
                            sheet.SetColumnWidth(column.Ordinal, (arrColWidth[column.Ordinal] + 1)*300);
                        }
                        //   headerRow.Dispose();
                    }

                    #endregion

                    rowIndex = 1;
                }

                #endregion

                #region 填充内容

                IRow dataRow = sheet.CreateRow(rowIndex);
                foreach (DataColumn column in dtSource.Columns)
                {
                    ICell newCell = dataRow.CreateCell(column.Ordinal);

                    string drValue = row[column].ToString();

                    switch (column.DataType.ToString())
                    {
                        case "System.String": //字符串类型   
                            newCell.SetCellValue(drValue);
                            break;
                        case "System.DateTime": //日期类型   
                            DateTime dateV;
                            DateTime.TryParse(drValue, out dateV);
                            newCell.SetCellValue(dateV);

                            newCell.CellStyle = dateStyleDateTime; //格式化显示   
                            break;
                        case "System.Boolean": //布尔型   
                            bool boolV;
                            bool.TryParse(drValue, out boolV);
                            newCell.SetCellValue(boolV);
                            break;
                        case "System.Int16": //整型   
                        case "System.Int32":
                        case "System.Int64":
                        case "System.Byte":
                            int intV;
                            int.TryParse(drValue, out intV);
                            newCell.SetCellValue(intV);
                            break;
                        case "System.Decimal": //浮点型   
                        case "System.Double":
                            double doubV;
                            double.TryParse(drValue, out doubV);
                            newCell.SetCellValue(doubV);
                            newCell.CellStyle = dateStyleMoney;
                            break;
                        case "System.DBNull": //空值处理   
                            newCell.SetCellValue("");
                            break;
                        default:
                            newCell.SetCellValue("");
                            break;
                    }
                }

                #endregion

                rowIndex++;
            }


            using (var ms = new MemoryStream())
            {
                workbook.Write(ms);
                ms.Flush();
                ms.Position = 0;

                // sheet.Dispose();
                //workbook.Dispose();//一般只用写这一个就OK了，他会遍历并释放所有资源，但当前版本有问题所以只释放sheet   
                return ms;
            }
        }

        /// <summary>
        /// 读取excel，默认第一行为标头
        /// </summary>
        /// <param name="strFileName">excel文档绝对路径</param>
        /// <returns>数据表</returns>
        public static DataTable Import(string strFileName)
        {
            var dt = new DataTable();

            HSSFWorkbook hssfworkbook;
            using (var file = new FileStream(strFileName, FileMode.Open, FileAccess.Read))
            {
                hssfworkbook = new HSSFWorkbook(file);
            }
            ISheet sheet = hssfworkbook.GetSheetAt(0);
            IEnumerator rows = sheet.GetRowEnumerator();

            IRow headerRow = sheet.GetRow(0);
            int cellCount = headerRow.LastCellNum;

            for (int j = 0; j < cellCount; j++)
            {
                ICell cell = headerRow.GetCell(j);
                dt.Columns.Add(cell.ToString());
            }

            for (int i = (sheet.FirstRowNum + 1); i <= sheet.LastRowNum; i++)
            {
                IRow row = sheet.GetRow(i);
                DataRow dataRow = dt.NewRow();

                for (int j = row.FirstCellNum; j < cellCount; j++)
                {
                    if (row.GetCell(j) != null)
                        dataRow[j] = row.GetCell(j).ToString();
                }

                dt.Rows.Add(dataRow);
            }
            return dt;
        }

        /// <summary>
        /// 获取excel第一列
        /// </summary>
        /// <param name="fileName">excel的绝对路径</param>
        /// <returns>excel列名</returns>
        public static IList<string> GetExcelHead(string fileName)
        {
            IList<string> list = new List<string>();
            HSSFWorkbook hssfworkbook;
            using (var file = new FileStream(fileName, FileMode.Open, FileAccess.Read))
            {
                hssfworkbook = new HSSFWorkbook(file);
            }
            IRow headerRow = hssfworkbook.GetSheetAt(0).GetRow(0);
            int cellCount = headerRow.LastCellNum;

            for (int j = 0; j < cellCount; j++)
            {
                ICell cell = headerRow.GetCell(j);
                list.Add(cell.ToStr());
            }
            return list;
        }
    }
}